/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.connection.parser.json.itemparsers;

import com.google.gjson.JSONArray;
import com.google.gjson.JSONException;
import com.google.gjson.JSONObject;
import com.hercules.android.receiver.connection.parser.CommandParsingException;
import com.hercules.android.receiver.connection.parser.MalformedCommandException;
import com.hercules.android.receiver.connection.parser.json.ItemParser;

/**
 * Parser for JSON field values. It checks if required values are present.
 * <p>
 * AndroidAssembly2 this class was added in Android Assembly 2
 *
 * @author 7realm
 * @version 1.0
 */
public abstract class FieldParser extends ItemParser {
    /**
     * Protected constructor for {@link FieldParser}.
     *
     * @param required if property is required
     */
    protected FieldParser(boolean required) {
        super(required);
    }

    /**
     * Parses JSON key value.
     *
     * @param path the path to value
     * @param json the JSON
     * @param keyName the name of current JSON key
     * @param instance the instance of object, parsed value will be set to it
     * @param setterType describes how value should be set to instance
     * @return the parsed value
     * @throws CommandParsingException if error occurs while parsing
     */
    @Override
    public Object parse(StringBuilder path, JSONObject json, String keyName, Object instance, SetterType setterType)
        throws CommandParsingException {
        if ("*".equals(keyName) || json.containsKey(keyName)) {
            // get value
            Object value = doParse(path, json, keyName, instance);

            // set and return value
            setValue(path, keyName, instance, value, setterType);
            return value;
        } else if (isRequired()) {
            throw new MalformedCommandException("Missing required field '" + path + "'. JSON: '" + json + "'.");
        }

        // optional value, this will be ignored
        return null;
    }

    /**
     * Parses JSON array item value.
     *
     * @param path the path to value
     * @param jsonArray the JSON array
     * @param index the name of current item in array
     * @param instance the instance of object, parsed value will be set to it
     * @param setterType describes how value should be set to instance
     * @return the parsed value
     * @throws CommandParsingException if error occurs while parsing
     */
    @Override
    public Object parse(StringBuilder path, JSONArray jsonArray, int index, Object instance, SetterType setterType)
        throws CommandParsingException {
        try {
            // create temp JSON object
            JSONObject temp = new JSONObject();
            String keyName = Integer.toString(index);
            temp.put(keyName, jsonArray.get(index));

            // call parse
            return parse(path, temp, keyName, instance, setterType);
        } catch (JSONException e) {
            throw new MalformedCommandException("Failed to get JSON field at index '" + index + "'. JSON array '"
                + jsonArray + "'.", e);
        }
    }

    /**
     * Parses the property that is present.
     *
     * @param path the path to value
     * @param json the JSON
     * @param keyName the name of current JSON key
     * @param instance the instance of object, parsed value will be set to it
     * @return the parsed value
     * @throws CommandParsingException if error occurs while parsing
     */
    protected abstract Object doParse(StringBuilder path, JSONObject json, String keyName, Object instance)
        throws CommandParsingException;

}
